package Scuttlebutt;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import glue.ftp.*;
import glue.*;
import java.io.*;
import java.util.*;
import javax.swing.tree.*;
import java.awt.dnd.*;

public class Scuttlebutt extends JFrame 
{
  	private final static MouseAdapter mouseAdapter = new MouseAdapter() {};	
	private Project project = null;
    private FtpBean ftp = null;

	private MyPanels panels = null;
	private MenuBar menuBar = null;
    
	private String remote_home_directory = null;
	private Settings settings = null;
	
	private ButtonBar buttons = null;
	
	PrintStream out = null;
	PrintStream stdOut = null;
	
	public class NameFilter implements FilenameFilter{
		String ext = null;
		public NameFilter(String ext){
			this.ext = ext;
		}
		
		public boolean accept(File dir, String name) {
			return (name.endsWith(ext));
		}
	}
	
	public class JMessageOutputStream extends OutputStream{
//		JTextArea outText = null;
		FileWriter fw = null;
		public JMessageOutputStream(/*JTextArea text*/){
//			this.outText = text;
			try{
				fw = new FileWriter("log.txt");
			}catch(IOException io){
				System.err.print(io.getMessage());
			}
			
//			w.close();
//			b.close();
			
//			w = null;
//			b = null;
		}
		
		public void write(byte[] b, int off, int len){
//			outText.setText(new String(b).substring(off,len));
//		 	JOptionPane.showMessageDialog(null, new String(b).substring(off,len), "Error", JOptionPane.ERROR_MESSAGE);
			String msg = new String(b).substring(off,len);
			try{
				BufferedWriter bw = new BufferedWriter(fw);
				bw.write("OK\n", 0, 3);
				bw.write(msg, 0, msg.length());
				bw.close();
			}catch(IOException io){
				System.err.print(io.getMessage());
			}
		}
		
		public void write(int b){
		}
	}
	
	
	
	
	public Settings getSettings(){
		return settings;
	}
	
	class SWindowListner implements WindowListener{
		Scuttlebutt parent = null;
	public SWindowListner(Scuttlebutt parent){
		this.parent = parent;
	}
	
	public void windowOpened(WindowEvent e){
	}
	
	public void windowClosing(WindowEvent e){
		parent.getEditPane().undoAllNotUploadedForNotSaved();
		parent.getSettings().setWindowState(parent.getExtendedState());
		parent.getSettings().setDivider(parent.getPanels().getTopDivider());
		parent.getSettings().setLowerDivider(parent.getPanels().getBottomDivider());
		
		parent.getSettings().saveSettings(settings);
		Project.Save(project);
		stdOut.close();
		System.setOut(out);
		System.exit(0);
	}
	
	public void windowClosed(WindowEvent e){
	}
	
	public void windowIconified(WindowEvent e){
	}
	
	public void windowDeiconified(WindowEvent e){
	}
	
	public void windowActivated(WindowEvent e){
	}
	
	public void windowDeactivated(WindowEvent e){
	}
	}
	
	
	class SComponentListener implements ComponentListener{
		Scuttlebutt parent = null;
		public SComponentListener(Scuttlebutt parent){
			this.parent = parent;
		}
	public void componentResized(ComponentEvent e){
		int state = ((JFrame)e.getComponent()).getExtendedState();
		if(( state & JFrame.MAXIMIZED_BOTH ) != JFrame.MAXIMIZED_BOTH ){
			parent.getSettings().setSettings(parent);
		}
	}
	
	public void componentMoved(ComponentEvent e){
		int state = ((JFrame)e.getComponent()).getExtendedState();
		if(( state & JFrame.MAXIMIZED_BOTH ) != JFrame.MAXIMIZED_BOTH ){
			parent.getSettings().setSettings(parent);
		}
	}
	
	public void componentShown(ComponentEvent e){
	}
	
	public void componentHidden(ComponentEvent e){
	}
	}

	
	public class TreeKeyListner implements KeyListener{
		Scuttlebutt parent = null;
		public TreeKeyListner(Scuttlebutt parent){
			this.parent = parent;
		}
		public void keyTyped(KeyEvent e){
		}
		
		public void keyPressed(KeyEvent e){
		}
		
		public void keyReleased(KeyEvent e){
			if(e.getKeyCode() == e.VK_DELETE){
				if( parent.getProject().getTree().getSelectionCount() == 0){
					return;
				}else{
					String msg = new String();
					TreePath[] paths = parent.getProject().getTree().getSelectionPaths();
					int count = parent.getProject().getTree().getSelectionCount();
					for(int x = 0; x < count; x++){
						msg += "\t";
						msg += ((DefaultMutableTreeNode)paths[x].getLastPathComponent()).toString();
						msg += "\n";
					/*	if(count >= 2){
							if(x < count - 2){
								msg += ", ";
							}else if(x < count - 1){
								msg += " & ";
							}
							
						}*/
					}
					
					if(JOptionPane.showConfirmDialog(null, new String("You are about to delete:\n" + msg +"This operation cannot be undone. Do you wish to continue?" ), "Warning", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION){
						ArrayList<Object> dirList = new ArrayList<Object>();
						for(int x = 0; x < count; x++){
							
							Object o = paths[x].getLastPathComponent();
							String path = new String(new String((((SortableNode)o).getRemoteDirectory().length() > 0)?new String(((SortableNode)o).getRemoteDirectory() + File.separatorChar):"") + ((SortableNode)o).toString());
							if (o instanceof FolderNode ) {
								System.out.println("add \"" + o.toString() + "\" to list");
								dirList.add(o);
							}else if (o instanceof URLNode ){
								((URLNode)o).removeFromParent();
							}else if (o instanceof SortableNode ){
								if(parent.isConnected())/* && (((SortableNode)o).isUploaded()))*/{
									try{
										parent.getFTP().fileDelete(path);
									}catch(java.io.IOException ioe){
										System.err.println(ioe);
									}catch(FtpException ftpe){
										System.err.println("Failed to delete file:" + ftpe);
									}
								}
								SortableNode node = (SortableNode)o;
								File f = new File(node.getNodePath());
								f.delete();
								((FolderNode)node.getParent()).remove(node);
								node.removeFromParent();
//								parent.getProject().getTree().removeSelectionPath(paths[x]);
							}
							
							parent.updateTree();
							
						}
						Object [] list = dirList.toArray();
						System.out.println("delete folder");
						System.out.println("list size " + dirList.size());
						for(Object n : list){
							System.out.println("node:" + n.toString() + " children count:" + ((FolderNode)n).getChildCount());
							if(((FolderNode)n).getChildCount() == 0){
								File f = new File(((FolderNode)n).getNodePath());
								System.out.println("delete " + f.getPath());
								if(f.getName().compareToIgnoreCase(parent.getRootNode().toString()) != 0){
									String path = new String(new String((((FolderNode)n).getRemoteDirectory().length() > 0)?new String(((FolderNode)n).getRemoteDirectory() + File.separatorChar):"") + ((FolderNode)n).toString());
									if(parent.isConnected())/* && (((SortableNode)o).isUploaded()))*/{
										try{
											parent.getFTP().removeDirectory(path);
										}catch(java.io.IOException ioe){
											System.out.println(ioe);
										}catch(FtpException ftpe){
											System.out.println("Failed to delete directory:" + ftpe);
										}
									}
									f.delete();
									((FolderNode)n).removeFromParent();
								}
							}else{
								
								for (Enumeration en = ((FolderNode)n).children() ; en.hasMoreElements() ;) {
									DefaultMutableTreeNode child = (DefaultMutableTreeNode)en.nextElement();
									System.out.println("child:" + child.toString());
								}
							}
						}
						parent.updateTree();
					}
				}
			}
		}
	}
	
	public Scuttlebutt()
	{
		remote_home_directory = new String("");
		out = System.out;
		try{
			stdOut= new PrintStream(new File("log.txt"));
		}catch(IOException io){
			System.err.print(io.getMessage());
		}
		System.setOut(stdOut);
		addComponentListener(new SComponentListener(this));
		settings = Settings.openSettings();	
		setBounds(settings.x, settings.y, settings.width, settings.height);
		setExtendedState(settings.getWindowState());
		initializeMethod();
		addWindowListener(new SWindowListner(this));
		project = new Project();
		project.getTree().setCellRenderer(new NodeRenderer());
		project.getTree().setTransferHandler(new NodeTransferHandler());
		project.getTree().addKeyListener(new TreeKeyListner(this));
		project.getTree().getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION/*DISCONTIGUOUS_TREE_SELECTION*/);
		project.getTree().setDropTarget(new DropTarget(project.getTree(), new TreeDropTargetListener(this)));	
		project.getTree().setDragEnabled(true);
//		project.getTree().setTransferHandler(new TreeTransferHandler());
		
		ftp = new FtpBean();
		buttons = new ButtonBar(this);
		add(buttons, BorderLayout.PAGE_START);
		panels = new MyPanels(this);
		menuBar = new MenuBar(this);
		setJMenuBar(menuBar);
		add(panels, BorderLayout.CENTER);
//		project.getTree().addTreeSelectionListener(new TreeListener(this));
		project.getTree().addMouseListener(new MouseEventHandler(this));
		setTitle();
		
	}
	
	public static void main(String[] sCommand)
	{
		Scuttlebutt app=new Scuttlebutt();
		app.setVisible(true);
	}

	private void initializeMethod()
	{
		Container container=getContentPane();
		container.setLayout(new BorderLayout());
	}
	
	public ButtonBar getButtonBar(){
		return buttons;
	}

	
	public MyPanels getPanels(){
		return panels;
	}
	
	public void createProject(){
		if(project == null){
			project = new Project();
		}
	}
	
	public void refreshMenu(){
		menuBar.removeAll();
		menuBar.createMenu(this);
		setJMenuBar(menuBar);
	}
	
	public Project getProject(){
		return project;
	}
	
	public void clearProject(){
	}
	
	public void setProject(Project project){
		this.project.clear();
		this.project.setProjectName(project.getProjectTitle());
		this.project.setProjectPath(project.getProjectPath());
		this.project.updateFTP(project.getFTPaddress(), project.getPort(), project.getUsername(), project.getPassword());
		this.project.setTreeModel(project.getTreeModel());
		this.project.setList(project.getList());
	}
	
	public void SaveProject(){
		Project.Save(project);
	}
	
	public FtpBean getFTP(){
		return ftp;
	}
	
	

    // Connect to a ftp server.
    
    public boolean connect()
    {
	    if(getProject().getFTPaddress().length() == 0)
	    	return false;
		setTitle(new String("Scuttlebutt ( ...trying to connect: " + getProject().getFTPaddress() + ")"));
        try
        {
            getFTP().ftpConnect(getProject().getFTPaddress(), getProject().getUsername(), getProject().getPassword());
//            getButtonBar().getConnectButton().setText("Disconnect");
        }catch(Exception e){
           	System.out.println(e);
		 	JOptionPane.showMessageDialog(null, e.toString(), "Error", JOptionPane.ERROR_MESSAGE);
           	return false;
        }
        try
        {
     	   setRemoteHomeDirectory(getFTP().getDirectory());
        }catch(Exception e){
            System.out.println("failed to get directory:" + e);
		 	JOptionPane.showMessageDialog(null, new String("failed to get directory:" + e), "Error", JOptionPane.ERROR_MESSAGE);
            return false;
        }
		getButtonBar().setConnectButtonDisconnect();
        getButtonBar().getConnectButton().setToolTipText("Disconnect");
        setTitle();
       	return isConnected();
    }
    
    public boolean isConnected(){
	    if(ftp == null)
	    	return false;
	    String info = new String("");	
		try
		{
	 	    info = ftp.getSystemType();
		}catch(IOException e){
            System.err.println("isConnected IOException:" + e);
		}catch(FtpException fe){
	        System.err.println("isConnected FtpException" + fe.getMessage());
		}
		
	    if((info == null) || (info.compareToIgnoreCase("null") == 0) || (info.compareToIgnoreCase("") == 0))
	    	return false;
	    else
	    	return true;
	}

    // Close connection
    public void close()
    {
		try
		{
            ftp.close();
//            getButtonBar().getConnectButton().setText("Connect");
			getButtonBar().setConnectButtonConnect();
            getButtonBar().getConnectButton().setToolTipText("Connect");
		}catch(IOException e){
            System.err.println("failed to close:" + e);
		}catch(FtpException fe){
	        System.err.println("failed to close" + fe.getMessage());
		}
		setTitle();
    }
	
	public String getRemoteHomeDirectory(){
		return remote_home_directory;
	}
	
	public void setRemoteHomeDirectory(String rhd){
		remote_home_directory = rhd;
	}
	
	public DefaultMutableTreeNode getRootNode(){
		return (DefaultMutableTreeNode)project.getTreeModel().getRoot();
	}
	
	public void updateTree(){
		project.getTree().updateUI();
	}
	
	public void saveProject(){
		Project.Save(project);
	}
	
	public EditPane getEditPane(){
		return panels.getEditPane();
	}
	
	public FileTransferTable getFileTransferTable(){
		return panels.getFileTransferTable();
	}

 	public void Synchronize(){
	 	
	 	if(!isConnected()){
		 	JOptionPane.showMessageDialog(null, "Error", "Not connected", JOptionPane.ERROR_MESSAGE);
	 	}else{
		 	SynchronizeDlg dlg = new SynchronizeDlg(this, "Synchronize");
		    dlg.setVisible(true);
		    saveProject();
	 	}
  	}
  	

  	public void setTitle(){
		String address = (isConnected()) ? project.getAddress() : new String("Not Connected");
		setTitle(new String("Scuttlebutt (" + address + ")"));
  	}
  	
    /** Returns an ImageIcon, or null if the path was invalid. */
    protected static ImageIcon createImageIcon(String path) {
        java.net.URL imgURL = Scuttlebutt.class.getResource(path);
        if (imgURL != null) {
            return new ImageIcon(imgURL);
        } else {
            System.err.println("Couldn't find file: " + path);
		 	JOptionPane.showMessageDialog(null, new String("Couldn't find file: " + path), "Error", JOptionPane.ERROR_MESSAGE);
            return null;
        }
    }
	
    public void setWaitCursor(boolean state){
//	    JRootPane rootpane =getRootPane();//getTopLevelAncestor();
//	    JComponent comp = (JComponent)rootpane.getGlassPane();
//	    RootPaneContainer root = (RootPaneContainer)comp.getTopLevelAncestor();

		Container c = getContentPane();
		if(state){
			c.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));//mouseAdapter
			getButtonBar().enableAllButtons(false);
			menuBar.enableMenus(false);
			project.getTree().setEnabled(false);
//			getEditPane().enableAllTabs(false);
	    }else{
		    c.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
		    menuBar.enableMenus(true);
		    getEditPane().enableAllTabs(true);
		    project.getTree().setEnabled(true);
	    }
    }
    
    
    public void newProject(String projectName, File projectPath, String ftpAddress, int port, String username, String password, boolean synchornize){
		project.setProjectName(projectName);
		project.setProjectPath(projectPath);
		project.updateFTP(ftpAddress, port, username, password);
  	 	File dir = new File(projectPath.getPath() + File.separatorChar + projectName);
  	 	if(!dir.exists()){
  	 		dir.mkdir();
  	 	}
 
	  	FolderNode root = (FolderNode)getRootNode();
		root.setNodePath(dir.getPath());
		root.setUserObject(projectName);
		root.setUploaded(true);
		getButtonBar().getConnectButton().setEnabled(false);
		if((connect()) && (synchornize)){
			Synchronize();
		}
		
		root.setRemoteDirectory(getRemoteHomeDirectory());	
		
   		getButtonBar().getConnectButton().setEnabled(true);
		getButtonBar().enableNewProjectButton(false);
		getButtonBar().enableOpenProjectButton(false);
		setTitle();
   	 	updateTree();
		saveProject(); 		   	
		RecentProjects rp = RecentProjects.open();
		File f = new File(projectPath.getPath() + File.separatorChar + projectName + File.separatorChar + projectName + ".prj");
		rp.addProject(projectName,f);
		RecentProjects.save(rp);
		refreshMenu();
    }
    
	public class OpenProjectThread implements Runnable{
		File projectDir = null;
		Scuttlebutt parent = null;
		public OpenProjectThread(Scuttlebutt parent, File projectDir){
			this.parent = parent;
			this.projectDir = projectDir;
		}
		
		public void run(){
			parent.setProject(Project.Open(projectDir));
			parent.setWaitCursor(true);
			parent.getButtonBar().getConnectButton().setEnabled(false);
			int size = parent.getProject().getOpendCount();
			Object [] openList = parent.getProject().getOpenedList();
			for(Object o : openList){
				parent.getEditPane().OpenWithoutCheck(o.toString());
			}
			
			
			parent.connect();
			recurseDirectoryForDownloadingNodes(parent.getRootNode());
			parent.getFileTransferTable().startDownloading();
			parent.setTitle();
			parent.updateTree();
			parent.getButtonBar().getConnectButton().setEnabled(true);
			parent.getButtonBar().enableSaveProjectButton(true);
			parent.getButtonBar().enableCloseProjectButton(true);
			parent.setWaitCursor(false);
		}
		
		private void recurseDirectoryForDownloadingNodes(DefaultMutableTreeNode o){
			for (Enumeration e = o.children() ; e.hasMoreElements() ;) {
				DefaultMutableTreeNode node = (DefaultMutableTreeNode)e.nextElement();
		        if (node instanceof FolderNode ) {
			        recurseDirectoryForDownloadingNodes(node);
		        }else if(node instanceof URLNode){
		        }else if (node instanceof SortableNode ){//file
			        SortableNode s = (SortableNode)node;
					File f = new File(s.getNodePath());
					if(f.exists()){					
						if(s.getProgress() > 0){
							Download d = new Download(parent, s);
							parent.getFileTransferTable().addDownload(d);
						}
			        }else{
				        parent.getProject().removeOpened(s.getNodePath());
				        parent.getEditPane().remove(s.getNodePath());
				        s.removeFromParent();
					}
		        }
			}
		}	
	}
     
    public void loadProject(File file){
	    if((!file.isDirectory()) && (file.getPath().endsWith(".prj"))){
	    	new Thread(new OpenProjectThread(this, file)).start();
	    }else{
		    System.out.println("That project doesn't exist");
/*		    
			File selectedFile = chooser.getSelectedFile();
			File p = null;
			if(file.isDirectory()){
				String [] flist = file.list(new NameFilter(new String(".prj")));
				for(String f : flist){
					p = new File(new String(file.getPath() + File.separatorChar + f));
				}
			}else{
				p = file;
			}
		    
		    
		    
		    FolderNode node = null;
			int idx = p.getPath().lastIndexOf("\\");
			File path = new File(p.getPath().substring(0,idx));
			project.setProjectName(path.getName());
			project.setProjectPath(path);
			project.updateFTP("127.0.0.1", 21, "anonymous", "");
			node = (FolderNode)getRootNode();
			node.setNodePath(p.getPath());
			node.setUserObject(p.getName());
			node.setUploaded(true);
			node.setRemoteDirectory("");
	    
			RecentProjects rp = RecentProjects.open();
			rp.addProject(path.getName(),p);
			RecentProjects.save(rp);
			refreshMenu();
			saveProject();*/
	    }
   	}
}

